package com.hh.consumer.controller;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class ConsumerController {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    /**
     * ribbon 是怎么将 http://provider/hello 路径请求成功的
     * http://127.0.0.1:8080/hello
     * 1. 拦截这个请求
     * 2. 截取主机名称
     * 3. 借助eureka来做服务发现 通过服务名称拿到服务集合
     * 4. 通过负载均衡算法 拿到一个服务ip port
     * 5. reConstructURL 重构
     * 6. 发起请求
     * @param serviceName
     * @return
     */
    @GetMapping("testRibbon")
    public String testRibbon(String serviceName) {
        // 正常来讲 需要 拿到ip和port 以及 路径 才可以用
        // http://provider/hello
        String result = restTemplate.getForObject("http://" + serviceName + "/hello", String.class);
        // 只要给restTemplate 加了 ribbon 的注解 项目中这个对象发起的请求 都会走ribbon的代理
        // 如果你想使用原生的 只要给restTemplate 只需要重新创建一个对象
        // 最好先启动提供者
        // 如果时先启动的消费者 那你就等一会儿再玩 等个半分钟左右
//        RestTemplate myRest = new RestTemplate();
//        String forObject = myRest.getForObject("http://localhost:8888/aaa", String.class);
        return result;
    }

    // 轮训的算法 怎么去实现
    // 两台机器 A B
    // 第一次访问A
    // 第二次访问B
    // A
    // B
    // A
    // 代码实现轮训算法 List<机器>
    // 请求次数
    // int index = 1 % size list.get(index);
    // 取模 取余 好处是一个周期函数 让得到的结果总是 小于 除数
    // 1 / 2        1 % 2
    // 1 % 2 = 1
    // 2 % 2 = 0
    // 3 % 2 = 1
    // 4 % 2 = 0
    // 全局顶一个 int i = 0
    // i ++ 线程不安全的
    // i % size
    // 怎么做一个线程安全的轮训算法 加锁 效率极低 CAS 自旋锁 没有线程的等待和唤醒的开销
    // CAS 有点 性能好 无锁的 java层面无锁的状态 但是在jvm 层面 是有锁的
    // CAS 缺点 会导致短暂时间内CPU飙升 还有 ABA 问题
    // CAS 操作包含的三个操作数
    // 1. 内存位置 V
    // 2. 预期原值 A
    // 3. 新增 B

    /**
     * ribbon 核心是负载均衡
     * @param serviceName
     * @return
     */
    @GetMapping("/testRibbonRule")
    public String testRibbonRule(String serviceName) {
        ServiceInstance choose = loadBalancerClient.choose(serviceName);
        return choose.toString();
    }
}
